﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using BlueLotus7.Common;
using BlueLotus7.WeiboApiLibrary.Weibo.Contracts;

namespace BlueLotus7.WeiboApiLibrary
{
    internal static partial class ContentAnalyzer
    {
        private const string bodyStartTag = "<body>";
        private const string bodyEndTag = "</body>";
        private const string tag_src = "src";
        private const string tag_href = "href";
        private const string tag_div = "div";
        private const string tag_form = "form";
        private const string tag_a = "a";
        private const string tag_input = "input";
        private const string tag_id = "id";
        private const string attr_type = "type";
        private const string attr_value = "value";
        private const string attrValue_hidden = "hidden";

        private const string class_Comment = "c";
        private const string class_CommentToTarget = "ctt";
        private const string class_CommentTime = "ct";

        private const string html_space = "&nbsp;";

        private const string content_fromConstString = "来自";
        private const string content_replyConstString = "回复:";
        private const string content_weiboConstString = "微博";
        private const string content_followsConstString = "关注";
        private const string content_fansConstString = "粉丝";

        /// <summary>
        /// Figure out body content
        /// </summary>
        /// <param name="htmlContent"></param>
        /// <returns></returns>
        private static string CleanHtmlContent(string htmlContent)
        {
            string result = string.Empty;

            if (!string.IsNullOrWhiteSpace(htmlContent))
            {
                int bodyStart = htmlContent.IndexOf(bodyStartTag);
                int bodyEnd = htmlContent.IndexOf(bodyEndTag);

                if (bodyStart < bodyEnd && bodyStart > -1)
                {
                    result = htmlContent.Substring(bodyStart, bodyEnd + bodyEndTag.Length - bodyStart);
                    result = result.Replace("&nbsp;", string.Empty);
                }
            }

            return result;
        }

        /// <summary>
        /// Load binary by specific uri.
        /// </summary>
        /// <param name="uri">Uri instance</param>
        /// <returns>Byte array of data.</returns>
        internal static byte[] LoadBinary(Uri uri)
        {
            byte[] result = null;
            byte[] buffer = new byte[4096];

            WebRequest request = WebRequest.Create(uri);

            using (WebResponse response = request.GetResponse())
            {
                using (Stream responseStream = response.GetResponseStream())
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        int count = 0;
                        do
                        {
                            count = responseStream.Read(buffer, 0, buffer.Length);
                            memoryStream.Write(buffer, 0, count);

                        } while (count != 0);

                        result = memoryStream.ToArray();
                    }
                }
            }

            return result;
        }

        #region Xml operation utility

        private static string GetXmlAttributeValue(XmlNode xmlNode, string attributeName)
        {
            string result = string.Empty;

            if (xmlNode != null && !string.IsNullOrWhiteSpace(attributeName))
            {
                XmlAttribute attribute = xmlNode.Attributes[attributeName];
                if (attribute != null)
                {
                    result = attribute.Value == null ? string.Empty : attribute.Value;
                }
            }

            return result;
        }

        private static string GetXmlAttributeValue(XElement xNode, string attributeName)
        {
            string result = string.Empty;

            if (xNode != null && !string.IsNullOrWhiteSpace(attributeName))
            {
                XAttribute attribute = xNode.Attributes(attributeName).Single();
                if (attribute != null)
                {
                    result = attribute.Value == null ? string.Empty : attribute.Value;
                }
            }

            return result;
        }

        #endregion

        private static Dictionary<string, string> TranslateUrlParameters(string url)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();

            if (!string.IsNullOrWhiteSpace(url))
            {
                int index = url.IndexOf("?");
                int length = url.Length - index - 1;
                if (index > -1 && length > 0)
                {
                    url = url.Substring(index + 1, url.Length - index - 1);
                }

                string[] parameters = url.Split('&');
                foreach (string parameter in parameters)
                {
                    if (!string.IsNullOrWhiteSpace(parameter))
                    {
                        string[] keyvalue = parameter.Split('=');
                        if (keyvalue.Length == 2)
                        {
                            string key = keyvalue[0];
                            string value = keyvalue[1];

                            if (!result.ContainsKey(key))
                            {
                                result.Add(key, value);
                            }
                        }
                    }
                }
            }

            return result;
        }

        #region Next page operations

        //<div class="pa" id="pagelist">
        //    <form action="/u/2710243353?st=46a5" method="post">
        //    <div>
        //        <a href="/u/2710243353?page=3&amp;st=46a5">下页</a>&nbsp;
        //        <a href="/u/2710243353?page=1&amp;st=46a5">上页</a>&nbsp;
        //        <a href="/u/2710243353?st=46a5">首页</a>&nbsp;
        //        <input name="mp" type="hidden" value="14">
        //        <input type="text" name="page" size="2" style="-wap-input-format: &quot; *n&quot;">
        //        <input type="submit" value="跳页">&nbsp;2/14页
        //    </div>
        //    </form>
        //</div>

        /// <summary>
        /// Gets page panel xml
        /// </summary>
        /// <param name="bodyContentXml">Body content xml</param>
        /// <returns>Page panel node instance.</returns>
        private static XElement GetPagePanelXml(XElement bodyContentXml)
        {
            XElement pagePanel = null;

            if (bodyContentXml != null)
            {
                var query = from element in bodyContentXml.Elements(tag_div) where GetXmlAttributeValue(element, tag_id).Equals("pagelist", StringComparison.InvariantCultureIgnoreCase) select element;
                if (query != null && query.Count() > 0)
                {
                    pagePanel = query.Single();
                }
            }

            return pagePanel;
        }

        /// <summary>
        /// Gets total page count by page panel node
        /// </summary>
        /// <param name="pagePanelXml">Page panel node instance.</param>
        /// <returns>Page count value.</returns>
        private static int GetTotalPageCountByPagePanelNode(XElement pagePanelXml)
        {
            int pageNumber = 0;

            if (pagePanelXml != null)
            {
                var query = from e in pagePanelXml.Elements(tag_form).Elements(tag_div).Elements(tag_input) where GetXmlAttributeValue(e, attr_type).Equals(attrValue_hidden, StringComparison.InvariantCultureIgnoreCase) select e;

                if (query != null && query.Count() > 0)
                {
                    Int32.TryParse(GetXmlAttributeValue(query.Single(), attr_value), out pageNumber);
                }
            }

            return pageNumber;
        }

        /// <summary>
        /// Gets total page count by body xml
        /// </summary>
        /// <param name="bodyContentXml">Body content xml</param>
        /// <returns>Page count value.</returns>
        private static int GetTotalPageCountByBodyXml(XElement bodyContentXml)
        {
            return GetTotalPageCountByPagePanelNode(GetPagePanelXml(bodyContentXml));
        }

        #endregion

        #region Invoke delegate

        private static DelegateResult InvokeDelegate(WeiboArticle article, WeiboArticleDelegate delegateToInvoke, object delegateObject)
        {
            DelegateResult result = new DelegateResult();

            if (article != null && delegateToInvoke != null)
            {
                try
                {
                    result = delegateToInvoke.Invoke(article, delegateObject);
                }
                catch (Exception ex)
                {
                    result.Exception = ex;
                }
            }

            return result;
        }

        private static DelegateResult InvokeDelegate(WeiboUser user, WeiboUserDelegate delegateToInvoke, object delegateObject)
        {
            DelegateResult result = new DelegateResult();

            if (user != null && delegateToInvoke != null)
            {
                try
                {
                    result = delegateToInvoke.Invoke(user, delegateObject);
                }
                catch (Exception ex)
                {
                    result.Exception = ex;
                }
            }

            return result;
        }

        private static DelegateResult InvokeDelegate(WeiboArticle article, WeiboArticleDetailDelegate delegateToInvoke, object delegateObject)
        {
            DelegateResult result = new DelegateResult();

            if (article != null && delegateToInvoke != null)
            {
                try
                {
                    result = delegateToInvoke.Invoke(article, delegateObject);
                }
                catch (Exception ex)
                {
                    result.Exception = ex;
                }
            }

            return result;
        }

        private static DelegateResult InvokeDelegate(WeiboGroup group, WeiboGroupDelegate delegateToInvoke, object delegateObject)
        {
            DelegateResult result = new DelegateResult();

            if (group != null && delegateToInvoke != null)
            {
                try
                {
                    result = delegateToInvoke.Invoke(group, delegateObject);
                }
                catch (Exception ex)
                {
                    result.Exception = ex;
                }
            }

            return result;
        }

        #endregion
    }
}
